


// 校验单元格配置格式
interface RegExpValidatorConfItem {
  key: string;            // 关键key
  type: RegExpType | RegExpType[];   // 校验内置类型
  name: string;           // 校验项名称
  require?: boolean;      // 是否必填 value值
}

// 校验单元格式
interface RegExpValidatorItem extends RegExpValidatorConfItem {
  value: any;         // 待校验值
}

// 校验失败单元 - 多个TYPE
interface RegExpValidatorErrorItemGroup {
  type: RegExpType;   // 校验内置类型
  msg: string;
}

// 校验失败单元 - 单一TYPE
interface RegExpValidatorErrorItem extends RegExpValidatorItem {
  msg?: string | Array<RegExpValidatorErrorItemGroup>;
}

// 单数据校验返回参数
interface exceOnceResponse {
  validPassState: boolean;
  validErrors: Array<RegExpValidatorErrorItemGroup> | string;
}

// 校验返回格式
interface RegExpValidatorErrorResponse {
  validPassState: boolean;
  validErrors: Array<RegExpValidatorErrorItem>;
}

// 校验配置
interface RegExpValidatorInter {
  [x: string]: RegExpValidatorItem;
}

// 参数
interface RegExpValidatorOptions {
  regConfig: RegExpValidatorConfItem[];
}


export enum RegExpType {
  CN = 'CN',                          // 中文
  EN = 'EN',                          // 英文字母
  EN_NUMBER = 'EN_NUMBER',            // 任意英文+数字
  DECIMAL = 'DECIMAL',                // 小数浮点数类型
  INTEGER = 'INTEGER',                // 整数类型 - 正负都可以
  POSITIVE_INTEGER = 'POSITIVE_INTEGER',  // 整数类型 - 正数
  UP_ZERO_INTEGER = 'UP_ZERO_INTEGER',    // 0+正数 (<=0)
  UP_ONE_INTEGER = 'UP_ONE_INTEGER',      // 1+正数 (<=1)
  NUMBER = 'NUMBER',                // 数字类型
  EMAIL = 'EMAIL',                  // 电子邮箱
  PHONE = 'PHONE',                  // 手机 18165221849
  TEL = 'TEL',                      // 电话 0731-5632575
  PHONE_TEL = 'PHONE_TEL',          // 手机 + 电话
  POSTCODE = 'POSTCODE',            // 邮政编码
  HTTP = 'HTTP',                    // http (支持 - :post,www,ip,http,https)
  IP = 'IP',                        // ip地址
  IDENTITY_CARD = 'IDENTITY_CARD',  // 身份证
  SYMBOL_CN = 'SYMBOL_CN',          // 全角
  SYMBOL_EN = 'SYMBOL_EN'           // 半角
}


export default class RegExpValidator {

  private validPassState = true;                        // 最终的验证状态
  private regConfig: RegExpValidatorInter = {};         // 存储的配置校验 - 全量
  private validExcePool: RegExpValidatorItem[] = [];    // 本次执行 - 需要校验的组 （从 总仓regConfig 提取到 本次validExcePool）
  private validErrors: Array<RegExpValidatorErrorItem> = [];     // 错误集合

  iThis = this;

  constructor(options: RegExpValidatorOptions) {
    this.setOptions(options);
  }

  // 设置配置内容
  setOptions(options: RegExpValidatorOptions) {
    if (options) {
      const { regConfig } = options;
      
      if (regConfig) {
        let jsonConf: RegExpValidatorInter | any = {};
        regConfig.forEach(item => {
          jsonConf[item.key] = item;
        });
        this.regConfig = jsonConf;
      }
    }
  }

  // 执行
  exceValid = (formObj: { [x: string]: any; }): RegExpValidatorErrorResponse | never => {
    try {
      this.validPassState = true;

      let pools: RegExpValidatorItem[] = [];

      Object.keys(formObj).forEach(ikey => {
        let itemConf = this.regConfig[ikey];
        if (itemConf) {
          itemConf['value'] = formObj[ikey];
          pools.push(itemConf);
        }
      });

      this.validExcePool = pools;
      this.inlayVerify();

      return {
        validPassState: this.validPassState,
        validErrors: this.validErrors
      }
    } catch(err) {
      console.log('Bamboo-RegExpValidator: ', err);
      throw Error(err);
    }
  }

  // 执行单一 - 可以无视配置执行任意单次单个数据验证
  static exceOnce = (value: any, type: RegExpType | RegExpType[]): exceOnceResponse => {

    let response: exceOnceResponse | any = {};

    if (typeof type === 'object' && Array.isArray(type)) {
      let _validPassState = true;
      let _validError: RegExpValidatorErrorItemGroup[] = [];

      type.forEach(regType => {
        const iRunResp = ____iRun(regType);
        if (iRunResp) {
          const { validPassState, validErrors } = iRunResp;

          !validPassState && (_validPassState = true);
          _validError.push({ type: regType, msg: validErrors});
        }
      });

      response = {
        validPassState: _validPassState,
        validErrors: _validError
      };

    } else if (typeof type === 'string') {
      response = ____iRun(type);
    }


    function ____iRun(_type: RegExpType) {
      let getValid = RegExpValidator.___Valid(_type as RegExpType);

      if (getValid) {
        let [ regExp, msgText ] = getValid;

        if (!regExp || !regExp.test(value)) {      // item 验证不通过
          return {
            validPassState: false,
            validErrors: msgText
          };
        } else {
          return {
            validPassState: true,
            validErrors: ''
          };
        }
      }
    }
    return response;
  }



  // 非空则校验
  inlayVerify = (_valids?: RegExpValidatorItem[]) => {

    let valids = _valids || this.validExcePool;

    valids.forEach((item, index) => {

      /* if (typeof item.value === 'undefined') {
        throw Error('[lyq:Error at REGEXPverify.js] regexp error, the item not find [value]');
      } */

      if (
        item.require
      ) {
        // 必填情况
        if (this.isEmpty(item)) {
          this.validErrors.push({
            ...item,
            msg: '不能为空'
          });
          this.validPassState = false;
        } else {
          if (item.type && Array.isArray(item.type)) {

            let eJson = { ...item };
            let errs: RegExpValidatorErrorItemGroup[] = [];

            item.type.forEach(iType => {
              eJson.type = iType;
              let iErr = this._testRegExp(eJson, true);
              iErr && errs.push(iErr as RegExpValidatorErrorItemGroup);
            });

            this.validErrors.push({
              ...item,
              msg: errs
            });

          } else {
            let iErr = this._testRegExp(item);
            iErr && this.validErrors.push(iErr as RegExpValidatorErrorItem);
          }
        }
      } else if (!item.require) {
        // 允许不填, 一旦有值则对应类型验证
        if (!this.isEmpty(item)) {
          if (item.type && Array.isArray(item.type)) {

            let eJson = { ...item };
            let errs: RegExpValidatorErrorItemGroup[] = [];

            item.type.forEach(iType => {
              eJson.type = iType;
              let iErr = this._testRegExp(eJson, true);
              iErr && errs.push(iErr as RegExpValidatorErrorItemGroup);
            });

            this.validErrors.push({
              ...item,
              msg: errs
            });
          } else {
            let iErr = this._testRegExp(item);
            iErr && this.validErrors.push(iErr as RegExpValidatorErrorItem);
          }
        }
      }
    });
    return this.validPassState;
  }

  // 验证器
  static ___Valid (TYPE: RegExpType): [RegExp, string] | void {
    let regexp: RegExp | null = null;
    let errText: string | null = null;

    switch(TYPE) {
      // 中文
      case RegExpType.CN: {
        regexp = /^[\u0391-\uFFE5]+$/;
        errText = '仅允许中文汉字';
      };break;
      // 英文字母
      case RegExpType.EN: {
        regexp = /^[a-zA-Z]+$/;
        errText ='仅允许英文字母';
      };break;
      // 任意英文+数字
      case RegExpType.EN_NUMBER: {
        regexp = /^[a-zA-Z0-9]+$/;
        errText ='仅允许英文及数字';
      };break;
      // 小数浮点数类型
      case RegExpType.DECIMAL: {
        regexp = /^\d+(\.\d+)?$/;
        errText = '必须是小数';
      };break;

      // 整数类型 - 正负都可以
      case RegExpType.INTEGER: {
        regexp = /^-?[1-9]\d+$/;
        errText ='必须是整数';
      };break;
      // 整数类型 - 正数
      case RegExpType.POSITIVE_INTEGER: {
        regexp = /^[0-9]*[1-9][0-9]*$/;
        errText = '必须是正整数';
      };break;

      // 0+正数
      case RegExpType.UP_ZERO_INTEGER: {
        regexp = /^(0|\+?[1-9][0-9]*)$/;
        errText ='必须是大于等于0的整数';
      };break;

      // 1+正数
      case RegExpType.UP_ONE_INTEGER: {
        regexp = /^(1|\+?[1-9][0-9]*)$/;
        errText ='必须是大于等于1的整数';
      };break;

      // 数字类型
      case RegExpType.NUMBER: {
        regexp = /^-?[0-9]\d+$/;
        errText ='必须是数字';
      };break;

      // 邮箱
      case RegExpType.EMAIL: {
        regexp = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/;
        errText ='邮箱格式错误';
      };break;

      // 手机 18165221849
      case RegExpType.PHONE: {
        regexp = /^1\d{10}$/;
        errText ='必须是手机号码';
      };break;

      // 电话 0731-5632575
      case RegExpType.TEL: {
        regexp = /^0\d{2,3}-?\d{7,8}$/;
        errText ='必须是电话号码';
      };break;

      // 手机 + 电话
      case RegExpType.PHONE_TEL: {
        regexp = /^1\d{10}$|^0\d{2,3}-?\d{7,8}$/;
        errText ='必须是手机或电话号码';
      };break;

      // 邮政编码
      case RegExpType.POSTCODE: {
        regexp = /^\d{6}$/;
        errText ='必须是6位数字';
      };break;

      // http (支持 - :post,www,ip,http,https)
      case RegExpType.HTTP: {
        regexp = /[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/;
        errText ='必须是正确url地址';
      };break;

      // ip地址
      case RegExpType.IP: {
        regexp = /(\d+)\.(\d+)\.(\d+)\.(\d+)/;
        errText ='必须是正确ip格式';
      };break;

      // 身份证 - 15位 | 18位 | 17+X
      case RegExpType.IP: {
        regexp = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;   // 15位 | 18位 | 17+X
        errText ='必须是正确身份证';
      };break;

      // 符号匹配 - 半角
      case RegExpType.SYMBOL_EN: {
        regexp = /[\x00-\xff]/;   // 半角符号
        errText ='必须是半角';
      };break;

      // 符号匹配 - 全角
      case RegExpType.SYMBOL_CN: {
        regexp = /[^\x00-\xff]/;   // 全角符号
        errText ='必须是全角';
      };break;
      
    }

    if (regexp && errText) {
      return [ regexp, errText ];
    }
  }

  /**
   * 正则校验
   * @param item        校验对象
   * @param continuous  是否连贯 （true - 多个type的校验、false/ undefined - 单个type校验）- 为确保输出验证格式
   */
  _testRegExp (item: RegExpValidatorItem, continuous?: boolean): RegExpValidatorErrorItem | RegExpValidatorErrorItemGroup | void {

    let getValid = RegExpValidator.___Valid(item.type as RegExpType);

    if (getValid) {
      let [ regExp, msgText ] = getValid;

      if (!regExp || !regExp.test(item.value)) {      // item 验证不通过

        this.validPassState = false;

        let iError: RegExpValidatorErrorItem | RegExpValidatorErrorItemGroup = {
          ...item,
          msg: msgText || ''
        };

        if (continuous) {
          iError = {
            type: item.type,
            msg: msgText || ''
          } as RegExpValidatorErrorItemGroup;
        }

        return iError;
      }
    }
  }

  // 判断当前值是否为空
  private isEmpty = (item: RegExpValidatorItem) => {  // 必填

    if (!item.value || item.value.toString().trim() === '') {
      /* Message({
        type: 'error',
        message: item.name + '不能为空!'
      }) */
      return true;
    }
    return false;
  }

}